<template>
  <div v-if="comments.length > 0" class="comment-panel">
    <div class="comment-panel-header">
      <h3>批注 ({{ comments.length }})</h3>
    </div>
    <div class="comment-panel-content">
      <DynamicVirtualList
        ref="virtualListRef"
        :data="filteredComments"
        :estimated-height="120"
        :buffer="3"
        item-key="id"
        :reset-scroll-on-data-change="false"
        :highlighted-item-key="activeCommentId || undefined"
        @scroll-to-bottom="handleScrollToBottom"
        @item-visible="handleItemVisible"
      >
        <template #default="{ item }">
          <CommentItem
            :comment="item as Comment"
            :active-comment-id="activeCommentId"
            @select="handleSelectComment"
            @scroll-to-item="handleScrollToItem"
            @scroll-to-reply="handleScrollToReply"
          />
        </template>
      </DynamicVirtualList>
      <div v-if="filteredComments.length === 0" class="comment-empty">
        <el-empty description="暂无批注" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  computed,
  ref,
  inject,
  nextTick,
  watch,
  onBeforeUnmount,
  type Ref,
} from "vue";
import type { Editor } from "@tiptap/vue-3";
import { DynamicVirtualList } from "../virtual/index";
import CommentItem from "./CommentItem.vue";
import type { Comment } from "../../types/comment";
import { commentStore, commentActions } from "../../store/comment";
import {
  highlightCommentMark,
  scrollToCommentPosition,
} from "../../utils/commentEditor";

defineOptions({
  name: "CommentPanel",
});

const emit = defineEmits<{
  (e: "select-comment", commentId: string): void;
}>();

const editor = inject<Ref<Editor>>("editor");
const virtualListRef = ref<InstanceType<typeof DynamicVirtualList>>();
const comments = computed(() => commentActions.getAllComments());
const activeCommentId = computed(() => commentStore.activeCommentId);
const filter = ref<"all" | "unresolved">("all");

const filteredComments = computed(() => {
  if (filter.value === "unresolved") {
    return comments.value.filter((c) => !c.isResolved);
  }
  return comments.value;
});

const handleSelectComment = (commentId: string) => {
  const comment = commentActions.getComment(commentId);
  if (comment && editor?.value) {
    const { state } = editor.value;
    const docSize = state.doc.content.size;
    const safeFrom = Math.max(0, Math.min(comment.position.from, docSize));
    const safeTo = Math.max(0, Math.min(comment.position.to, docSize));

    // 检查位置是否有效
    if (safeFrom >= docSize || safeTo > docSize) {
      console.warn(
        `批注位置无效，无法跳转: from=${comment.position.from}, to=${comment.position.to}, docSize=${docSize}`
      );
      return;
    }

    try {
      // 跳转到批注位置
      editor.value.commands.setTextSelection({
        from: safeFrom,
        to: safeTo,
      });

      // 高亮编辑器中的批注标记
      nextTick(() => {
        highlightCommentMark(editor.value!, commentId);
        // 滚动编辑器视图到批注位置
        scrollToCommentPosition(editor.value!, safeFrom, safeTo);
      });
    } catch (error) {
      console.warn("设置文本选择失败:", error);
    }

    // 设置活动批注
    commentActions.setActiveComment(commentId);
    emit("select-comment", commentId);
  }
};

const handleScrollToItem = (commentId: string) => {
  // 滚动虚拟列表到对应项
  nextTick(() => {
    virtualListRef.value?.scrollToItem(commentId, {
      offset: -20,
      behavior: "smooth",
    });
  });
};

// 处理滚动到回复
// 注意：这个函数现在主要用于兼容性，实际滚动逻辑已经在CommentItem中处理
const handleScrollToReply = (replyId: string) => {
  // 找到包含该回复的批注
  const comment = filteredComments.value.find((c) =>
    c.replies?.some((r) => r.id === replyId)
  );
  if (comment) {
    // 先滚动到批注项（确保批注项可见）
    nextTick(() => {
      virtualListRef.value?.scrollToItem(comment.id, {
        offset: -20,
        behavior: "smooth",
      });
    });
  }
};

const handleScrollToBottom = () => {
  // 滚动到底部的处理
};

const handleItemVisible = (
  _item: unknown,
  _index: number,
  _isVisible: boolean
) => {
  // 项可见性变化的处理
};

// 组件挂载状态
let isComponentMounted = true;

// 定时器引用
let scrollTimer: ReturnType<typeof setTimeout> | null = null;

const scrollToComment = (commentId: string) => {
  if (!commentId || !virtualListRef.value) return;

  const exists = filteredComments.value.some(
    (comment) => comment.id === commentId
  );
  if (!exists) return;

  // 清理之前的定时器
  if (scrollTimer) {
    clearTimeout(scrollTimer);
    scrollTimer = null;
  }

  nextTick(() => {
    if (!isComponentMounted) return;
    nextTick(() => {
      if (!isComponentMounted) return;
      scrollTimer = setTimeout(() => {
        if (virtualListRef.value && isComponentMounted) {
          virtualListRef.value.scrollToItem(commentId, {
            offset: -20,
            behavior: "smooth",
          });
        }
        scrollTimer = null;
      }, 100);
    });
  });
};

// 组件卸载时清理
onBeforeUnmount(() => {
  isComponentMounted = false;
  if (scrollTimer) {
    clearTimeout(scrollTimer);
    scrollTimer = null;
  }
});

// 监听活动批注ID变化，高亮编辑器中的标记
watch(
  activeCommentId,
  (newId) => {
    if (editor?.value) {
      // 高亮编辑器中的批注标记
      nextTick(() => {
        highlightCommentMark(editor.value!, newId);

        // 如果有新的活动批注，滚动编辑器视图到该位置
        if (newId) {
          const comment = commentActions.getComment(newId);
          if (comment && editor.value) {
            const { state } = editor.value;
            const docSize = state.doc.content.size;
            const safeFrom = Math.max(
              0,
              Math.min(comment.position.from, docSize)
            );
            const safeTo = Math.max(0, Math.min(comment.position.to, docSize));

            // 检查位置是否有效
            if (safeFrom < docSize && safeTo <= docSize) {
              scrollToCommentPosition(editor.value, safeFrom, safeTo);
            } else {
              console.warn(
                `批注位置无效，无法滚动: from=${comment.position.from}, to=${comment.position.to}, docSize=${docSize}`
              );
            }
          }
        }
      });
    }
    if (newId) {
      scrollToComment(newId);
    }
  },
  { immediate: false }
);
</script>

<style lang="scss" scoped>
.comment-panel {
  width: 400px;
  flex-shrink: 0;
  height: 100%;
  background: var(--comment-panel-background);
  border: none;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  padding: 0 16px;
  border-left: 1px solid var(--comment-border-color);

  .comment-panel-header {
    padding: 16px 0;
    border-bottom: 1px solid var(--comment-divider-color);
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-shrink: 0;

    h3 {
      margin: 0;
      font-size: 16px;
      font-weight: 500;
      color: var(--editor-text-color);
    }
  }

  .comment-panel-content {
    flex: 1;
    overflow: hidden;
    padding: 0;
    display: flex;
    flex-direction: column;
    min-height: 0; // 确保 flex 子元素可以收缩
  }

  .comment-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--editor-text-color-light);
  }
}

.comment-item {
  padding: 16px;
  margin-bottom: 12px;
  border-radius: 8px;
  border: 2px solid var(--comment-item-border-color);
  background: var(--comment-item-background);
  transition: all 0.2s ease;
  cursor: pointer;

  &:hover {
    background: var(--comment-item-hover-background);
  }

  &.active {
    border-color: var(--comment-item-border-color-active);
    background: var(--comment-item-background-active);
  }

  &.resolved {
    opacity: 0.7;
  }
}

.comment-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 12px;
}

.comment-author {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
}

.author-avatar-wrapper {
  flex-shrink: 0;
}

.author-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
}

.author-avatar-placeholder {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  font-size: 14px;
  font-weight: 600;
}

.author-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

.author-name {
  font-weight: 600;
  font-size: 14px;
  color: var(--editor-text-color);
  line-height: 1.4;
}

.comment-time {
  font-size: 12px;
  color: var(--comment-time-color);
  line-height: 1.4;
}

.comment-status {
  flex-shrink: 0;
}

.resolved-badge {
  display: inline-block;
  padding: 2px 8px;
  background: var(--comment-resolved-bg);
  color: var(--comment-resolved-color);
  font-size: 11px;
  border-radius: 12px;
  font-weight: 500;
}

.comment-body {
  margin-bottom: 12px;
}

.comment-content {
  font-size: 14px;
  line-height: 1.6;
  word-break: break-word;
  color: var(--editor-text-color);
  margin-bottom: 12px;

  :deep(p) {
    margin: 0 0 8px 0;
    &:last-child {
      margin-bottom: 0;
    }
  }

  :deep(ul),
  :deep(ol) {
    margin: 8px 0;
    padding-left: 20px;
  }
}

.comment-replies {
  margin-top: 12px;
  padding-top: 12px;
  padding-left: 24px; // 添加缩进以区分批注和回复
}

.comment-reply {
  margin-bottom: 16px;

  &:last-child {
    margin-bottom: 0;
  }
}

.reply-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.reply-author-avatar-wrapper {
  flex-shrink: 0;
}

.reply-author-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
}

.reply-author-avatar-placeholder {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
}

.reply-author-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--editor-text-color);
}

.reply-content {
  font-size: 13px;
  line-height: 1.5;
  word-break: break-word;
  color: var(--editor-text-color);
  margin-bottom: 6px;

  :deep(p) {
    margin: 0 0 4px 0;
    &:last-child {
      margin-bottom: 0;
    }
  }
}

.reply-time {
  font-size: 11px;
  color: var(--comment-time-color);
  line-height: 1.4;
}

.reply-expand-actions {
  margin-top: 8px;
  padding-top: 8px;
}

.comment-footer {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--comment-divider-color);
}

.comment-reply-input {
  margin-top: 8px;
}

.comment-footer-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
</style>
